package com.cloud.note.service.impl;

import com.cloud.note.dto.auth.LoginRequest;
import com.cloud.note.dto.auth.LoginResponse;
import com.cloud.note.dto.auth.RegisterRequest;
import com.cloud.note.dto.auth.TokenRefreshResponse;
import com.cloud.note.model.User;
import com.cloud.note.model.UserToken;
import com.cloud.note.repository.UserRepository;
import com.cloud.note.repository.UserTokenRepository;
import com.cloud.note.security.JwtTokenProvider;
import com.cloud.note.service.AuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.UUID;

@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private UserTokenRepository userTokenRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JwtTokenProvider tokenProvider;

    @Override
    public LoginResponse login(LoginRequest loginRequest) {
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        loginRequest.getUsername(),
                        loginRequest.getPassword()));

        SecurityContextHolder.getContext().setAuthentication(authentication);

        // 获取用户信息
        User user = userRepository.findByUsername(loginRequest.getUsername())
                .orElseThrow(() -> new RuntimeException("用户不存在"));

        // 更新最后登录时间
        user.setLastLoginAt(LocalDateTime.now());
        userRepository.save(user);

        // 生成令牌
        String jwt = tokenProvider.generateToken(authentication);

        // 保存令牌到数据库
        saveUserToken(user.getId(), jwt);

        return LoginResponse.builder()
                .token(jwt)
                .userId(user.getId())
                .username(user.getUsername())
                .build();
    }

    @Override
    @Transactional
    public LoginResponse register(RegisterRequest registerRequest) {
        // 检查用户名是否已存在
        if (userRepository.existsByUsername(registerRequest.getUsername())) {
            throw new RuntimeException("用户名已存在");
        }

        // 检查邮箱是否已存在
        if (userRepository.existsByEmail(registerRequest.getEmail())) {
            throw new RuntimeException("邮箱已存在");
        }

        // 创建新用户
        User user = new User();
        user.setId(UUID.randomUUID().toString());
        user.setUsername(registerRequest.getUsername());
        user.setPassword(passwordEncoder.encode(registerRequest.getPassword()));
        user.setEmail(registerRequest.getEmail());
        user.setPremium(false);
        user.setStorageUsed(0L);
        user.setStorageLimit(1073741824L); // 1GB
        user.setCreatedAt(LocalDateTime.now());
        user.setLastLoginAt(LocalDateTime.now());

        userRepository.save(user);

        // 生成令牌
        String jwt = tokenProvider.generateToken(user.getId());

        // 保存令牌到数据库
        saveUserToken(user.getId(), jwt);

        return LoginResponse.builder()
                .token(jwt)
                .userId(user.getId())
                .username(user.getUsername())
                .build();
    }

    @Override
    @Transactional
    public TokenRefreshResponse refreshToken(String token) {
        if (!tokenProvider.validateToken(token)) {
            throw new RuntimeException("令牌无效或已过期");
        }

        String userId = tokenProvider.getUserIdFromJWT(token);
        String newToken = tokenProvider.generateToken(userId);
        LocalDateTime expiryDate = LocalDateTime.now().plusSeconds(tokenProvider.getExpirationInSeconds());

        // 更新令牌
        userTokenRepository.findByToken(token).ifPresent(userToken -> {
            userToken.setToken(newToken);
            userToken.setExpiresAt(expiryDate);
            userTokenRepository.save(userToken);
        });

        return TokenRefreshResponse.builder()
                .token(newToken)
                .expiresAt(expiryDate)
                .build();
    }

    @Override
    @Transactional
    public void logout(String token) {
        userTokenRepository.findByToken(token).ifPresent(userToken -> {
            userTokenRepository.delete(userToken);
        });
    }

    private void saveUserToken(String userId, String token) {
        // 删除该用户的旧令牌
        userTokenRepository.deleteByUserId(userId);

        // 保存新令牌
        UserToken userToken = new UserToken();
        userToken.setId(tokenProvider.generateUserTokenId());
        userToken.setUserId(userId);
        userToken.setToken(token);
        userToken.setExpiresAt(LocalDateTime.now().plusSeconds(tokenProvider.getExpirationInSeconds()));

        userTokenRepository.save(userToken);
    }
}